const fs = require("fs");
const path = require("path");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default; // 遍历ast的节点
const babel = require("@babel/core");

const moduleAnalyser = (filename) => {
  const content = fs.readFileSync(filename, "utf-8"); //获取文件
  //1. 获取到文件内容的ast内容
  const ast = parser.parse(content, {
    sourceType: "module", // Files with ES6 imports and exports are considered "module" and are otherwise "script".
  });
  console.log("ast", ast.program.body);
  const dependencies = {};
  // 遍历ast节点,获取到依赖文件路径
  traverse(ast, {
    ImportDeclaration({ node }) {
      console.log("node+", node);
      const dirname = path.dirname(filename);
      const newFile = "./" + path.posix.join(dirname, node.source.value); // 获取到依赖文件的相对与bundler的地址 path.posix讲'\'变为''/
      dependencies[node.source.value] = newFile;
    },
  });
  // console.log(dependencies);
  // {"./message.js":"./src/message.js"}

  //2. 解析ast文件内容transforming为浏览器可以识别的内容
  const { code } = babel.transformFromAst(ast, null, {
    presets: ["@babel/preset-env"],
  });
  // console.log('code')
  return {
    filename,
    dependencies,
    code,
  };
};
// 将所有的依赖组成依赖树
const makeDependenciesGraph = (entry) => {
  const entryModule = moduleAnalyser(entry);
  const graphArray = [entryModule];
  for (let i = 0; i < graphArray.length; i++) {
    const item = graphArray[i];
    const { dependencies } = item;
    if (Object.keys(dependencies).length) {
      for (let j in dependencies) {
        graphArray.push(moduleAnalyser(dependencies[j]));
      }
    }
  }
  // console.log(graphArray);
  const graph = {};
  graphArray.forEach((item) => {
    graph[item.filename] = {
      dependencies: item.dependencies,
      code: item.code,
    };
  });
  return graph;
};

// console.log(graphInfor)

// 将生成的依赖树变成浏览器可以运行的代码  generating阶段

const generateCode = (entry) => {
  const graph = JSON.stringify(makeDependenciesGraph(entry));
  return `
    (function (graph) {
        function require(module) {
            function localRequire(relativePath){
                return require(graph[module].dependencies[relativePath])
            };
            var exports = {};
            (function (require,exports,code) {
                eval(code)
            })(localRequire,exports,graph[module].code)
            return exports
        };
        require('${entry}');
    })(${graph})
    `;
};

const code = generateCode("./src/index.js");
console.log(code);
